package com.kjlink.widget.monitoring.schedule.handle;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.kjlink.common.util.JsonUtil;
import com.kjlink.widget.monitoring.constant.MonitorConstant;
import com.kjlink.widget.monitoring.entity.MonitorRawEvent;
import com.kjlink.widget.monitoring.enums.EventTypeEnum;
import com.kjlink.widget.monitoring.helper.MonitorModelBuilderHelper;
import com.kjlink.widget.monitoring.model.BaseMonitorDataExtraModel;
import com.kjlink.widget.monitoring.model.MonitorDataModel;
import com.kjlink.widget.monitoring.processor.BaseMonitorEventProcessor;
import com.kjlink.widget.monitoring.service.EventBatchService;
import com.kjlink.widget.monitoring.service.EventConsumerService;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.*;

/**
 * 描述:
 * 定时从Redis消费事件并写入本地数据库
 *
 * @author Vic.xu
 * @since 2025-08-04 14:25
 */
@Component
public class MonitorEventConsumerHandler extends BaseMonitorEventProcessor {

    protected static ObjectMapper objectMapper = JsonUtil.objectMapper;

    public MonitorEventConsumerHandler(StringRedisTemplate stringRedisTemplate) {
        super(stringRedisTemplate);
    }


    @Resource
    private EventBatchService eventBatchService;

    @Resource
    private EventConsumerService eventConsumerService;

    @Resource
    private MonitorModelBuilderHelper monitorModelBuilderHelper;


    /**
     * 定时从Redis消费事件并写入本地数据库
     * 执行间隔可在配置文件中设置，默认1分钟
     */
    public List<String> consumeEventsFromRedis() {
        logger.info("Starting to consume events from Redis...");
        Set<String> keys = stringRedisTemplate.keys(MonitorConstant.KEY_PREFIX + "*");
        if (keys == null || keys.isEmpty()) {
            logger.info("No events found in Redis");
            return Collections.emptyList();
        }
        // 1. 获取全部 事件
        List<MonitorRawEvent> rawEvents = new ArrayList<>();
        // 保存 事件id 和 的映射  redis key方便后续删除
        Map<String, String> keyToEventIdMap = new HashMap<>();
        for (String key : keys) {
            MonitorRawEvent rawEvent = buildRawEventByRedisKey(key);
            if (rawEvent != null) {
                keyToEventIdMap.put(rawEvent.getEventId(), key);
                rawEvents.add(rawEvent);
            }
        }
        // 2 按 occurTime 升序排序  保证数据处理的顺序性
        rawEvents.sort(Comparator.comparing(MonitorRawEvent::getOccurTime));

        // 3 分别保存每一个事件 在新事务中
        // 处理后的 key 集合, 将会删除
        List<String> processedKeys = new ArrayList<>();
        for (MonitorRawEvent rawEvent : rawEvents) {
            try {
                eventConsumerService.saveRawEvent(rawEvent);
                // 找到对应的 key（这里假设 eventId 是唯一标识）
                String key = keyToEventIdMap.get(rawEvent.getEventId());
                if (key != null) {
                    processedKeys.add(key);
                }
                logger.info("Consumed event (type: {}) occurTime: {} eventId: {}",
                        rawEvent.getEventType(), rawEvent.getOccurTime(), rawEvent.getEventId());
            } catch (Exception e) {
                logger.error("Error processing event from Redis, key: {}", keyToEventIdMap.get(rawEvent.getEventId()), e);
            }
        }

        // 4. 删除已处理的key
        if (!processedKeys.isEmpty()) {
            stringRedisTemplate.delete(processedKeys);
            logger.info("Deleted {} processed event keys from Redis", processedKeys.size());
        }
        return processedKeys;
    }

    /**
     * 从Redis中构建MonitorRawEvent
     *
     * @param key Redis中的key
     */
    protected MonitorRawEvent buildRawEventByRedisKey(String key) {
        try {
            String value = stringRedisTemplate.opsForValue().get(key);
            if (value == null) {
                logger.error("Value is null for key: {}", key);
                return null;
            }
            logger.info("Consuming event from Redis, key: {}, value = {}", key, value);
            // 步骤1：先解析出事件类型
            // 将 json 解析为 JsonNode
            JsonNode rootNode = objectMapper.readTree(value);

            // 提取 eventType 字段的 JSON 数据
            JsonNode typeNode = rootNode.get("eventType");
            String typeString = typeNode != null ? typeNode.asText() : null;

            EventTypeEnum eventType = EventTypeEnum.getType(typeString);
            if (eventType == null) {
                logger.error("Event type is null, key: {}", key);
                return null;
            }

            // 步骤2：从枚举中获取该事件对应的extra具体类型
            Class<? extends BaseMonitorDataExtraModel> extraClass = eventType.getExtraClass();
            if (extraClass == null) {
                logger.error("No extra class defined for event type: {}", eventType);
                return null;
            }

            // 步骤3：构建带具体泛型的类型（MonitorDataModel<extraClass>）
            JavaType javaType = objectMapper.getTypeFactory()
                    .constructParametricType(MonitorDataModel.class, extraClass);

            // 步骤4：最终反序列化为带具体泛型的对象
            MonitorDataModel<? extends BaseMonitorDataExtraModel> dataModel =
                    objectMapper.readValue(value, javaType);

            // 转换
            MonitorRawEvent rawEvent = monitorModelBuilderHelper.buildRawEvent(dataModel);

            logger.info("Consumed event (type: {}) from Redis, eventId: {}",
                    eventType, dataModel.getEventId());
            return rawEvent;
        } catch (JsonProcessingException e) {
            logger.error("JSON parse error for key: {}", key, e);
        } catch (Exception e) {
            logger.error("Error processing event from Redis, key: {}", key, e);
        }
        return null;
    }

}
